<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>网易云热评用户分布及属性特征</title>
    <style type="text/css">
        body {
            background: rgba(189, 208, 236, 1);
        }
        
        div {
            background: rgba(189, 208, 236, 1);
            float: left;
        }
        
        .background {
            fill: none;
            pointer-events: all;
        }
        /* 选项按钮 */
        
        .dataset-button {
            margin: 2px 4px 2px 4px;
            border: 1px outset rgba(107, 164, 139, 0.69);
            border-radius: 40px;
        }
        
        .datatype-button {
            margin: 2px 4px 2px 4px;
            border: 1px outset rgba(107, 164, 139, 0.69);
            border-radius: 40px;
        }
        
        .shadow {
            fill: rgb(201, 113, 179);
        }
        /* 省市 */
        
        #states {
            stroke: #000;
            stroke-width: 1.5px;
        }
        
        #states text {
            fill: #000;
            stroke: none;
            text-anchor: middle;
            font-size: 10px;
        }
        
        #states .active {
            fill: rgb(100, 165, 218) !important;
        }
        
        #states text.active {
            font-size: 12px;
            font-weight: bold;
            fill: #fff;
            stroke-width: .5px;
            fill: #fff !important;
            stroke: #000;
        }
        /* 用户point */
        
        #cities .active {
            fill: rgb(100, 165, 218) !important;
        }
        
        #cities text.active {
            font-size: 8px;
            font-weight: bold;
            fill: #fff;
            stroke-width: .5px;
            fill: #fff !important;
            stroke: #000;
        }
        /* 显示用户详情数据的div */
        
        #popup {
            background-color: rgba(37, 35, 39, 0);
            position: fixed;
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100%;
            text-align: left;
            display: none;
        }
        
        #popup div {
            float: none;
        }
        
        #popup .bg {
            background-color: rgba(189, 208, 236, 1);
            margin: 13% 5% 2% 67%;
        }
        
        #popup .bg img {
            width: 250px;
            height: 250px;
        }
    </style>
    <script src="./js/d3.v3.min.js"></script>
    <script src="./js/queue.v1.min.js"></script>
</head>

<body>
    <div>
        <div id="div1"></div>
        <div style="width:500px; margin-left:50px; margin-top: 50px;">

            <div id="dataset-picker"> <label>数据选择：</label> </div>
            <br><br>
            <div id="datatype-picker" style="float:none"><label>属性选择：</label> </div>
            <br>
            <div id="shadow-info" style="float:none"> <label>隐藏操作：</label></div>
            <br><br><br><br><br><br><br>

            <div id="sector-chart"></div>
        </div>
        <!-- 隐藏div，点击用户后显示 -->
        <div id="popup">
            <div class="bg">
                <div>
                    <a id="user-home" href=""><img id="user-head" src="" alt="头像" /></a><br>(点击头像访问网易云主页)
                </div>
                <br><br>
                <div>昵称：<label id="user-nickname"></label></div>
                <div>所在城市：<label id="user-city"></label></div>
                <div>年龄：<label id="user-age"></label></div>
                <div>vip：<label id="user-vip"></label></div>
                <div>个人简介：<label id="user-signature"></label></div>

            </div>
        </div>




        <script>
            var width = 1100,
                sectorWidth = 300,
                sectorHeight = 300,
                height = 700,
                outerRadius = sectorWidth / 2, //外半径
                innerRadius = 0, //内半径
                //用于放大缩小的位置判定
                centered;

            var populationMap = {};
            var userColorScale;
            // 用户数据
            var datasets = ["./data/处理数据/users+coordinates.json",
                    "./data/处理数据/creators+coordinates.json"
                ],
                // 选择用户数据按钮的内容
                datasetMap = {
                    "./data/处理数据/users+coordinates.json": "热评用户",
                    "./data/处理数据/creators+coordinates.json": "活跃用户"
                },
                //vip种类，生日(年龄)，性别，实名认证状态，用户种类(0普通，1电台，2歌手，3音乐组织，4音乐人，200音乐达人，201视频达人，10知名人士，202生活资讯达人)
                dataTypeSets = ["vipType", "birthday", "gender", "authStatus", "userType"],
                //选择vip种类按钮的内容
                dataTypeSetMap = {
                    "vipType": "VIP种类",
                    "birthday": "年龄",
                    "gender": "性别",
                    "authStatus": "实名认证",
                    "userType": "用户种类"
                },
                //当前省市用户人口数据
                cityPopuSets = ["./data/处理数据/usersPopulation.csv", "./data/处理数据/creatorsPopulation.csv"],
                //按钮名称
                shadowButtonInfo = ["隐藏用户", "隐藏地图"];
            //年龄映射，网易云的birthday属性是经过加密的，无法反向解析出具体值，只能测试出区间范围的映射
            var ageMap = {
                    "40后": -946722651063,
                    "45后": -788869812305,
                    "50后": -631103383820,
                    "55后": -473336952713,
                    "60后": -315570526045,
                    "65后": -157717701588,
                    "70后": 48725002,
                    "75后": 157815442321,
                    "80后": 315581875683,
                    "85后": 473434711113,
                    "90后": 631201119132,
                    "95后": 788967565578,
                    "00后": 946733971496,
                    "05后": 1104586808395,
                    "10后": 1262353216211,
                    "15后": 1420119656571,
                }
                //当前选择数据，用于数据间的切换
            var nowData = datasets[0],
                nowType = dataTypeSets[0],
                nowCityPopu = cityPopuSets[0];

            //把世界经纬坐标映射成以甘肃为中心的地图坐标
            var projection = d3.geo.mercator()
                .center([103.5996, 35.6396]) //甘肃兰州东乡县
                .scale(750)
                .translate([0, 50]);
            // .mode("equidistant")
            // .origin([107, 32]) ///???
            // .scale(1000)
            // .translate([width / 2, height / 2]);

            var path = d3.geo.path()
                .projection(projection);
            //基础svg
            var svg = d3.select("#div1").append("svg")
                .attr("width", width)
                .attr("height", height);

            svg.append("rect")
                .attr("class", "background")
                .attr("width", width)
                .attr("height", height)

            //用于中国地图
            var g = svg.append("g")
                .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                .append("g")
                .attr("id", "states");

            //用户绘制城市点
            var g2 = svg.append("g")
                .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                .append("g")
                .attr("id", "cities");

            //默认扇形图
            var dataset = [{
                label: "A",
                count: 10
            }, {
                label: "B",
                count: 20
            }, {
                label: "C",
                count: 30
            }, {
                label: "D",
                count: 40
            }]
            var piedata = d3.layout.pie()
                .value(function(d) {
                    return d.count;
                });
            //将dataset转化为能被用元表示的数组
            var color = d3.scale.category10();

            var arc = d3.svg.arc()
                .outerRadius(outerRadius)
                .innerRadius(innerRadius); //生成缺少角度的弧

            //用于扇形图的svg
            var svg2 = d3.select("#sector-chart")
                .append("svg")
                .attr("width", sectorWidth)
                .attr("height", sectorHeight);

            //扇形图
            var g3 = svg2.selectAll("g")
                .data(piedata(dataset))
                .enter()
                .append("g")
                .attr("transform", "translate(" + (sectorWidth / 2) + "," + (sectorWidth / 2) + ")");

            g3.append("path")
                .attr("fill", function(d, i) {
                    return color(i);
                })
                .attr("d", arc); //为这个组的弧形s定义颜色与角度

            g3.append("text")
                .attr("transform", function(d) {
                    return "translate(" + arc.centroid(d) + ")"; //将text定义在每一个弧形的中央
                })
                .attr("text-anchor", "middle")
                .text(function(d) {
                    return d.value;
                });

            //调取数据后开始绘制
            queue()
                .defer(d3.json, "./data/数据资料/china.json")
                .defer(d3.csv, nowCityPopu)
                .defer(d3.json, nowData)
                .await(ready);



            function ready(error, china, population, users) {
                if (error) throw error;
                //先把上次绘制的东西去除，否则仅会机械的覆盖
                g.remove();
                drawProvinces(china, population);
                //处理用户数据，转换为d3可识别绘制的格式
                var points = dealUsersData(users, nowType);
                g2.remove();
                drawUsers(points);
                g3.remove();
                drawSector(points);

            }

            //绘制用户省市分布
            function drawProvinces(state, population) {
                //重新定义g，因为之前remove()了
                g = svg.append("g")
                    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                    .append("g")
                    .attr("id", "states");
                // 读取省市人口数据，并加入到全局的人口字典中
                for (let i = 0; i < population.length; i++) {
                    populationMap[population[i].name] = population[i].number;
                }
                //用户属性颜色插值范围
                // var colors = ["#DE9ECE", "#302010"];
                var colors = ["#BDDFBF", "#AAD6C5", "#AFCF8B", "#BECF6C", "#CFCF5D", "#CFBB3C", "#CF9338", "#CF6D17", "#D00F0F"];

                //使用分位数(quantile)来映射比例尺
                var heatmap = d3.scale.quantile()
                    //参数的输入域（用8个阈值将0到max分成9份）
                    //这里最大值在G上，如果直接返回d的话会默认为尾部的d.PF
                    .domain([0, 8, d3.max(population, function(d) {
                        return [d.number];
                    })])
                    //映射输出域的取值
                    .range(colors);
                //根据坐标数据绘制地图
                var states = g.selectAll("path")
                    .data(state.features)
                    .enter().append("path")
                    .attr("d", path)
                    .attr("id", function(d) {
                        return d.properties.name;
                    })
                    //根据人口信息添加热图颜色
                    .attr('fill', function(d) {
                        return heatmap(populationMap[d.properties.name])
                    })
                    //为每个省市添加点击事件，用户可以交互式的放大和缩小
                    .on("click", click)

                //为每个省市添加标签
                var labels = g.selectAll("text")
                    .data(state.features)
                    .enter().append("text")
                    //标签位置居中
                    .attr("transform", function(d) {
                        return "translate(" + path.centroid(d) + ")";
                    })
                    .attr("id", function(d) {
                        return 'label-' + d.properties.name;
                    })
                    .attr("dy", ".35em")
                    //标签和的地图点击事件相同
                    .on("click", click)
                    //当宏观全局查看的时候，标签为当前省市的名字为简称
                    .text(function(d) {
                        return d.properties.name;
                    });
            };

            /* 获得用户状态
             *  @param type:
             *           birthday
             *           vipType
             *           gender
             *           authStatus
             *           userType
             */
            function dealUsersData(users, type) {
                var points = [];
                for (let i = 0; i < users.length; i++) {
                    //设置用于绘制地图的信息
                    points[i] = {};
                    points[i].geometry = {};
                    points[i].type = "Feature";
                    points[i].geometry.type = "Point";
                    points[i].geometry.coordinates = users[i].coordinates;
                    //设置用户内部的信息
                    points[i].properties = {};
                    points[i].properties.userId = users[i].userId;
                    points[i].properties.nickname = users[i].nickname;
                    points[i].properties.signature = users[i].signature;
                    points[i].properties.avatarUrl = users[i].avatarUrl;
                    points[i].properties.city_name = users[i].city_name;
                    points[i].properties.birthday = users[i].birthday;
                    points[i].properties.vipType = users[i].vipType;
                    points[i].properties.gender = users[i].gender;
                    //身份验证状态
                    points[i].properties.authStatus = users[i].authStatus;
                    //0普通用户，2认证歌手，4网易音乐人
                    points[i].properties.userType = users[i].userType;
                }
                return points;
            }

            function getGenderColor(d) {
                //男
                if (d == 1) return "#5497ce";
                //女
                if (d == 2) return "#c971b3";
                return "#AAAAAA";
            }

            function getVipTypeColor(d) {
                //普通用户
                if (d == 0) return "#CCCC99";
                //普通vip
                if (d == 10) return "#FF3399";
                //黑胶vip
                if (d == 11) return "#663366";
            }

            function getauthStatusColor(d) {
                if (d == 0) return "#CCCC99";
                return "#663366";
            }

            function getUserTypeColor(d) {
                var pointColors = ["#BDDFBF", "#BECF6C", "#CFCF5D", "#CF9338", "#D00F0F"];
                if (d <= 4) return pointColors[d];
                return pointColors[3];
            }

            function getAgeColor(d) {
                var colors = ["#BDDFBF", "#AAD6C5", "#BECF6C", "#CFCF5D", "#CFBB3C", "#CF9338", "#CF6D17", "#D00F0F"];
                if (d >= ageMap["40后"] && d < ageMap["50后"]) return colors[7];
                if (d >= ageMap["50后"] && d < ageMap["60后"]) return colors[7];
                if (d >= ageMap["60后"] && d < ageMap["70后"]) return colors[7];
                if (d >= ageMap["70后"] && d < ageMap["80后"]) return colors[6];
                if (d >= ageMap["80后"] && d < ageMap["90后"]) return colors[5];
                if (d >= ageMap["90后"] && d < ageMap["00后"]) return colors[3];
                if (d >= ageMap["00后"] && d < ageMap["10后"]) return colors[1];
                if (d >= ageMap["10后"]) return colors[0];
                return "#AAAAAA";
            }
            //绘制城市及其人口热图
            function drawUsers(usersData) {
                // var pointColors = ["#f2fe28", "#d29157", "#5a9180", "#4dd98", "#1cddb1"];


                //用户绘制城市点
                g2 = svg.append("g")
                    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                    .append("g")
                    .attr("id", "cities");
                //绘制城市点分布
                g2.selectAll('path')
                    //从point引入数据
                    .data(usersData)
                    .enter()
                    .append('path')
                    //根据当前用户选择的属性进行不同颜色的选取
                    .attr('fill', (d, i) => {
                        if (nowType == "birthday") return getAgeColor(d.properties.birthday);
                        if (nowType == "vipType") return getVipTypeColor(d.properties.vipType);
                        if (nowType == "gender") return getGenderColor(d.properties.gender);
                        if (nowType == "authStatus") return getauthStatusColor(d.properties.authStatus);
                        if (nowType == "userType") return getUserTypeColor(d.properties.userType);
                        return "yellow";
                    })
                    //为了避免用户重叠，这里每个用户像周围随机移动-6到6的范围
                    .attr('transform', (v, i) => {
                        return `translate(${Math.random()*12 - 6},${Math.random()*12 -6})`
                    })
                    .attr('stroke', 'none')
                    .attr('d', path)
                    //添加点击放大事件
                    .on("click", click)
                    //当鼠标悬停时显示具体的用户信息
                    .append("title").text(function(d) {
                        return "\t\t" + d.properties.nickname + "\n" +
                            "城市：" + d.properties.city_name + "\n" +
                            "年龄：" + getAge(d.properties.birthday) + "\n" +
                            "vip：" + getVipType(d.properties.vipType) + "\n" +
                            "类型：" + getUserType(d.properties.userType) + "\n" +
                            "个人简介: " + d.properties.signature;
                    });




                //为每个城市点添加标签
                var labels = g2.selectAll("text")
                    .data(usersData)
                    .enter().append("text")
                    //标签位置居中
                    .attr("transform", function(d) {
                        return "translate(" + path.centroid(d) + ")";
                    })
                    .attr("id", function(d) {
                        return 'label-' + d.properties.userId;
                    })
                    .attr("dy", ".35em")
                    .on("click", click)
                    //当宏观全局查看的时候，标签隐藏
                    .text(function(d) {
                        return null;
                    });
            }

            function getAge(d) {
                if (d >= ageMap["40后"] && d < ageMap["45后"]) return "40后";
                if (d >= ageMap["45后"] && d < ageMap["50后"]) return "45后";
                if (d >= ageMap["50后"] && d < ageMap["55后"]) return "50后";
                if (d >= ageMap["55后"] && d < ageMap["60后"]) return "55后";
                if (d >= ageMap["60后"] && d < ageMap["65后"]) return "60后";
                if (d >= ageMap["65后"] && d < ageMap["70后"]) return "65后";
                if (d >= ageMap["70后"] && d < ageMap["75后"]) return "70后";
                if (d >= ageMap["75后"] && d < ageMap["80后"]) return "75后";
                if (d >= ageMap["80后"] && d < ageMap["85后"]) return "80后";
                if (d >= ageMap["85后"] && d < ageMap["90后"]) return "85后";
                if (d >= ageMap["90后"] && d < ageMap["95后"]) return "90后";
                if (d >= ageMap["95后"] && d < ageMap["00后"]) return "95后";
                if (d >= ageMap["00后"] && d < ageMap["05后"]) return "00后";
                if (d >= ageMap["05后"] && d < ageMap["10后"]) return "05后";
                if (d >= ageMap["10后"] && d < ageMap["15后"]) return "10后";
                if (d >= ageMap["15后"]) return "15后";
                return "未知";
            }

            function getauthStatus(d) {
                if (d == 0) return "未认证";
                if (d == 1) return "已认证";
                return "未知";
            }

            function getGender(d) {
                if (d == 1) return "男性";
                if (d == 2) return "女性";
                return "未知";
            }
            //(0普通，1电台，2歌手，3音乐组织，4音乐人，200音乐达人，201视频达人，10知名人士，202生活资讯达人)
            function getUserType(d) {
                if (d == 0) return "普通";
                if (d == 1) return "电台";
                if (d == 2) return "歌手";
                if (d == 3) return "音乐组织";
                if (d == 4) return "音乐人";
                if (d == 200) return "音乐达人";
                if (d == 201) return "音乐视频达人";
                if (d == 202) return "生活资讯达人";
                if (d == 10) return "知名人士";
                return "未知";
            }

            function getVipType(d) {
                if (d == 0) return "普通用户";
                if (d == 10) return "一般vip";
                if (d == 11) return "黑胶vip";
                return "未知";
            }
            // 绘制扇形图
            function drawSector(points) {
                //处理成扇形图可识别的数据格式
                var dataset = getSectorData(points);
                var piedata = d3.layout.pie()
                    .value(function(d) {
                        return d.count;
                    });
                g3 = svg2.selectAll("g")
                    .data(piedata(dataset))
                    .enter()
                    .append("g")
                    .attr("transform", "translate(" + (sectorWidth / 2) + "," + (sectorWidth / 2) + ")");
                //根据当前用户选择的属性绘制颜色
                g3.append("path")
                    .attr("fill", function(d, i) {
                        if (nowType == "birthday") return getAgeColor(d.data.data);
                        if (nowType == "vipType") return getVipTypeColor(d.data.data);
                        if (nowType == "gender") return getGenderColor(d.data.data);
                        if (nowType == "authStatus") return getauthStatusColor(d.data.data);
                        if (nowType == "userType") return getUserTypeColor(d.data.data);
                        return "yellow";
                    })
                    //为这个组的弧形s定义颜色与角度
                    .attr("d", arc);
                // 添加扇形图的文本标识
                g3.append("text")
                    .attr("transform", function(d) {
                        //将text定义在每一个弧形的中央
                        return "translate(" + arc.centroid(d) + ")";
                    })
                    .attr("text-anchor", "middle")
                    .text(function(d) {
                        //为了避免标签冲突，角度小于0.2的文字不显示
                        if (d.endAngle - d.startAngle <= 0.2) return "";
                        return d.data.name + ":" + d.data.count;
                    });
            }
            //根据points处理生成扇形图数据格式
            function getSectorData(points) {
                var dataset = [],
                    length = 0,
                    dataMap = {};
                //用户选择不同的属性，这里对应的数据也不一样
                if (nowType == "gender") {
                    for (let i = 0; i < points.length; i++) {
                        if (dataMap[points[i].properties.gender] != null) {
                            dataset[dataMap[points[i].properties.gender]].count++;
                        } else {
                            dataMap[points[i].properties.gender] = length++;
                            dataset[length - 1] = {};
                            dataset[length - 1].count = 1;
                            dataset[length - 1].name = getGender(points[i].properties.gender);
                            dataset[length - 1].data = points[i].properties.gender; //用于确定扇形图的颜色
                        }
                    }
                }

                if (nowType == "authStatus") {
                    for (let i = 0; i < points.length; i++) {
                        if (dataMap[points[i].properties.authStatus] != null) {
                            dataset[dataMap[points[i].properties.authStatus]].count++;
                        } else {
                            dataMap[points[i].properties.authStatus] = length++;
                            dataset[length - 1] = {};
                            dataset[length - 1].count = 1;
                            dataset[length - 1].name = getauthStatus(points[i].properties.authStatus);
                            dataset[length - 1].data = points[i].properties.authStatus;
                        }
                    }
                }

                if (nowType == "vipType") {
                    for (let i = 0; i < points.length; i++) {
                        if (dataMap[points[i].properties.vipType] != null) {
                            dataset[dataMap[points[i].properties.vipType]].count++;
                        } else {
                            dataMap[points[i].properties.vipType] = length++;
                            dataset[length - 1] = {};
                            dataset[length - 1].count = 1;
                            dataset[length - 1].name = getVipType(points[i].properties.vipType);
                            dataset[length - 1].data = points[i].properties.vipType;
                        }
                    }
                }
                //(0普通，1电台，2歌手，3音乐组织，4音乐人，200音乐达人，201视频达人，10知名人士，202生活资讯达人)
                if (nowType == "userType") {
                    for (let i = 0; i < points.length; i++) {
                        if (dataMap[points[i].properties.userType] != null) {
                            dataset[dataMap[points[i].properties.userType]].count++;
                        } else {
                            dataMap[points[i].properties.userType] = length++;
                            dataset[length - 1] = {};
                            dataset[length - 1].count = 1;
                            dataset[length - 1].name = getUserType(points[i].properties.userType);
                            dataset[length - 1].data = points[i].properties.userType;
                        }
                    }
                }

                if (nowType == "birthday") {
                    for (let i = 0; i < points.length; i++) {
                        var age = getAge(points[i].properties.birthday);
                        if (dataMap[age] != null) {
                            dataset[dataMap[age]].count++;
                        } else {
                            dataMap[age] = length++;
                            dataset[length - 1] = {};
                            dataset[length - 1].count = 1;
                            dataset[length - 1].name = age;
                            dataset[length - 1].data = points[i].properties.birthday;
                        }
                    }
                }
                // 去除掉那些未填写当前属性的用户信息
                var index = -1;
                for (let i = 0; i < dataset.length; i++) {
                    if (dataset[i].name == "未知") {
                        index = i;
                        dataset[i].count = 0;
                    }
                }
                if (index > -1) dataset.splice(index, 1);
                return dataset;
            }

            //鼠标点击事件
            function click(d) {
                //初始的视角中心偏差x，y和放大系数k
                var x = 0,
                    y = 0,
                    k = 1;
                //如果点中了该元素并且视图的中心不在该元素上
                if (d && centered !== d) {
                    //取得该元素的位置信息并调整中心
                    var centroid = path.centroid(d);
                    x = -centroid[0];
                    y = -centroid[1];
                    k = 4;
                    centered = d;
                } else {
                    centered = null;
                }

                //设定所有省市块只用当选中时才保持活跃状态(active)
                g.selectAll("path")
                    .classed("active", centered && function(d) {
                        return d === centered;
                    });
                //设定所有用户point只用当选中时才保持活跃状态(active)
                g2.selectAll("path")
                    .classed("active", centered && function(d) {
                        return d === centered;
                    });

                //设定所有省市没选中状态时显示名字
                g.selectAll("text")
                    .text(function(d) {
                        return d.properties.name;
                    })
                    .classed("active", false);
                //设定所有用户没选中状态时什么都不显示
                g2.selectAll("text")
                    .text(function(d) {
                        return null;
                    })
                    .classed("active", false);

                //如果当前为放大的状态
                if (centered) {
                    //通过id选择出当前中心位置的城市
                    g.select("#label-" + centered.properties.name)
                        //将其内容更改为详细信息：省市名称+用户数量
                        .text(function(d) {
                            return d.properties.name + ': ' + (populationMap[d.properties.name] || '0');
                        })
                        //选中时为活跃状态
                        .classed("active", centered && function(d) {
                            return d === centered;
                        });

                    //通过id选择出当前中心位置的用用户
                    g2.select("#label-" + centered.properties.userId)
                        //将其内容更改为详细信息：用户昵称
                        .text(function(d) {
                            showDetail(d);
                            return d.properties.nickname;
                        })
                        //选中时为活跃状态
                        .classed("active", centered && function(d) {
                            return d === centered;
                        });
                }

                //放大的动画效果，x，y为选中省市的中心与当前中心的偏移量，k为放大倍数
                //每次点击都会执行，不移动时x,y=0, k=1，表示偏移量为0，放大倍数为1
                g.transition()
                    .duration(1000)
                    .attr("transform", "scale(" + k + ")translate(" + x + "," + y + ")")
                    .style("stroke-width", 1.5 / k + "px");

                g2.transition()
                    .duration(1000)
                    .attr("transform", "scale(" + k + ")translate(" + x + "," + y + ")")
                    .style("stroke-width", 1.5 / k + "px");
            }

            //在id=popup的div中显示用户的具体信息
            function showDetail(d) {
                d3.select("#user-nickname").text(d.properties.nickname);
                d3.select("#user-city").text(d.properties.city_name);
                d3.select("#user-age").text(getAge(d.properties.birthday));
                d3.select("#user-vip").text(getVipType(d.properties.vipType));
                d3.select("#user-signature").text(d.properties.signature);
                d3.select("#user-head").attr("src", d.properties.avatarUrl);
                //网易云个人用户的主页，根据id即可索引到
                d3.select("#user-home").attr("href", "https://music.163.com/#/user/home?id=" + d.properties.userId)
                var popup = document.getElementById("popup");
                //显示该div
                popup.style.display = "block";
                //点击div则再次隐藏
                popup.onclick = function() {
                    //隐藏div
                    popup.style.display = "none";
                }

            }

            // 数据集选择按钮们
            var dataSetPicker = d3.select("#dataset-picker").selectAll(".dataset-button")
                .data(datasets);

            dataSetPicker.enter()
                .append("input")
                .attr("value", function(d) {
                    return datasetMap[d];
                })
                .attr("type", "button")
                .attr("class", "dataset-button")
                .on("click", function(d, i) {
                    nowData = d;
                    nowCityPopu = cityPopuSets[i];
                    queue()
                        .defer(d3.json, "./data/数据资料/china.json")
                        .defer(d3.csv, nowCityPopu)
                        .defer(d3.json, nowData)
                        .await(ready);
                });
            //属性类型选择按钮们
            var dataTypePicker = d3.select("#datatype-picker").selectAll(".datatype-button")
                .data(dataTypeSets);

            dataTypePicker.enter()
                .append("input")
                .attr("value", function(d) {
                    return dataTypeSetMap[d];
                })
                .attr("type", "button")
                .attr("class", "datatype-button")
                .on("click", function(d) {
                    nowType = d;
                    queue()
                        .defer(d3.json, nowData)
                        .await(drawCity);
                });

            //重新绘制用户的省市分布
            function drawCity(error, users) {
                if (error) throw error;
                var points = dealUsersData(users, nowType);
                g2.remove();
                drawUsers(points);
                g3.remove();
                drawSector(points);
            }

            var dataTypePicker = d3.select("#shadow-info").selectAll(".shadow-button")
                .data(shadowButtonInfo);

            dataTypePicker.enter()
                .append("input")
                .attr("value", function(d) {
                    return d;
                })
                .attr("type", "button")
                .attr("class", "datatype-button")
                .on("click", function(d, i) {
                    //隐藏用户
                    if (i == 0) {
                        g2.remove();
                        return;
                    }
                    //隐藏地图
                    if (i == 1) {
                        g.selectAll("path").attr("fill", "#AAAAAA");
                    }
                });
        </script>

</body>

</html>